/**
 * @file gt911.c
 * @brief GT911 Capacitive Touch Panel Controller Driver
 * @version 0.1
 * @date 2021-01-13
 * 
 * @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
 *
 *      Licensed under the Apache License, Version 2.0 (the "License");
 *      you may not use this file except in compliance with the License.
 *      You may obtain a copy of the License at
 *
 *               http://www.apache.org/licenses/LICENSE-2.0

 *      Unless required by applicable law or agreed to in writing, software
 *      distributed under the License is distributed on an "AS IS" BASIS,
 *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *      See the License for the specific language governing permissions and
 *      limitations under the License.
 */

#include "gt911.h"

static const char *TAG = "gt911";

uint8_t GT911_ADDR[2] = {0xba, 0xbb};


#define I2C_MASTER_NUM              0
#define ACK_CHECK_EN 0x1                        /*!< I2C master will check ack from slave*/
#define ACK_VAL 0x0                             /*!< I2C ack value */
#define NACK_VAL 0x1                            /*!< I2C nack value */

esp_err_t gt911_read_bytes(uint16_t reg_addr, size_t data_len, uint8_t *data)
{
	if (data_len == 0) {
        return ESP_OK;
    }
	i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
	i2c_master_write_byte(cmd, GT911_ADDR[0], ACK_CHECK_EN);
	uint8_t b = (reg_addr>>8); 
	i2c_master_write_byte(cmd, b, ACK_CHECK_EN);
	b = (reg_addr&0x00ff);
	i2c_master_write_byte(cmd, b, ACK_CHECK_EN);
	i2c_master_start(cmd);
	i2c_master_write_byte(cmd, GT911_ADDR[1], ACK_CHECK_EN);
	if (data_len > 1) {
		int i;
		for (i = 0; i < data_len - 1; i++) {
			i2c_master_read_byte(cmd, data + i, ACK_VAL);
		}

    }
    i2c_master_read_byte(cmd, data + data_len - 1, NACK_VAL);
	i2c_master_stop(cmd);
    esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_PERIOD_MS);
    i2c_cmd_link_delete(cmd);
	return ret;
  
}

esp_err_t gt911_write_bytes(uint16_t reg_addr, size_t data_len, uint8_t *data)
{
	int ret;
	i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
	i2c_master_write_byte(cmd, GT911_ADDR[0], ACK_CHECK_EN);
	uint8_t b;
	b = (reg_addr>>8); 
	i2c_master_write_byte(cmd, b, ACK_CHECK_EN);
	b = (reg_addr&0x00ff);
	i2c_master_write_byte(cmd, b, ACK_CHECK_EN);
	int i;
	for (i = 0; i < data_len; i++) {
		i2c_master_write_byte(cmd, data[i], ACK_CHECK_EN);
	}

	i2c_master_stop(cmd);
    ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_PERIOD_MS);
    i2c_cmd_link_delete(cmd);
	return ret;

}

esp_err_t gt911_init(void)
{
    if (ESP_OK != bsp_i2c_init(I2C_MASTER_NUM)) {
		ESP_LOGE(TAG, "bsp i2c init failed");
        return ESP_FAIL;
    }

    uint8_t temp[5] = {0};
    esp_err_t ret = ESP_OK;
    temp[0] = 0x02;
    ret |= gt911_write_bytes(GT_CTRL_REG, 1, temp);   //soft reset
	temp[0] = 0;
	gt911_write_bytes(GT_CTRL_REG, 1, temp);
	
	ret = gt911_read_bytes(GT_PID_REG, 4, temp); //read ic Product ID
	temp[4] = 0;
	if (ret != ESP_OK) { ESP_LOGE(TAG, "Read GT911 product id failed"); }
	ESP_LOGI(TAG, "tp driver ic:GT%s", temp);
	
    ret |= gt911_read_bytes(GT_CFGS_REG, 1, temp);    //read config version 
    ESP_LOGI(TAG, "tp config version:0x%02X", temp[0]);

    vTaskDelay(pdMS_TO_TICKS(20));

    if(ret == ESP_OK) ESP_LOGI(TAG, "gt911 init ok");
    else ESP_LOGI(TAG, "gt911 init fail");
	
	gt911_read_bytes(GT_CFGS_REG, 1, temp);
	ESP_LOGI(TAG, "Read config version:0x%02x", temp[0]);
	vTaskDelay(pdMS_TO_TICKS(20));
	
    return ret;
}

static esp_err_t gt911_get_touch_points_num(uint8_t *touch_points_num)
{
    uint8_t temp = 0;
    gt911_read_bytes(GT_GSTID_REG, 1, &temp);
    if (temp & 0x80) {
        *touch_points_num = temp & 0x0F;
        // ESP_LOGI(TAG, "reg=0x%X num=%d", temp, *touch_points_num);
        return ESP_OK;
    }
    else {
        *touch_points_num = 0;
        return ESP_FAIL;
    }
}

esp_err_t gt911_read_pos(uint8_t *touch_points_num, uint16_t *x, uint16_t *y)
{
    static uint8_t data[4];

    if(ESP_OK == gt911_get_touch_points_num(touch_points_num))
    {
        if (0 == *touch_points_num) {
        } else {
            gt911_read_bytes(GT_TP1_REG, 4, data);
            *x = ((data[1] & 0x0f) << 8) + data[0];
            *y = ((data[3] & 0x0f) << 8) + data[2];
			
        }

        data[0] = 0;
        gt911_write_bytes(GT_GSTID_REG, 1, data);
    }

    return ESP_OK;
}



